import threading
import time
import json
import queue
import numpy as np
from datetime import datetime
from collections import defaultdict
from congestion.RadarPhrase_new import get_info_from_raw
from congestion.traffic_flow_matrix_congestion_radar import Traffic_Flow_Radar
from congestion.traffic_flow_matrix_congestion_lidar import Traffic_Flow_LiDAR
from congestion.lidar_data_process import lidar_data_process
from congestion.KakouPhrase import kakou_data_process, time_difference, calculate_distance, kakou_in_tuunel_data_process


class ProcessCongestion:
    def __init__(self):
        self.plate_info = {}
        self.timestamp_B5 = 0
        self.timestamp_event = 0
        self.traffic_flow = Traffic_Flow_Radar()
        self.traffic_flows = {i: Traffic_Flow_LiDAR() for i in range(1, 9)}
        self.congestion_lidar_queue = queue.Queue()
        self.congestion_kakou_queue = queue.Queue()
        self.flag = False

    def kakou_congestion_detect(self):
        timestamp_now = time.time()
        dt = datetime.fromtimestamp(timestamp_now)
        if not len(self.plate_info):
            formatted_timestamp = dt.strftime('%Y-%m-%dT%H:%M:%S.') + str(dt.microsecond)[:3]
        else:
            formatted_timestamp = self.plate_info[list(self.plate_info.keys())[-1]][0][0][0]
        del_index = {}
        input_info = {}
        stake_info = {}
        time_thresh = 600
        stay_in_stake_veh_num = {}
        # print("拥堵算法执行中！")
        for plate, data in self.plate_info.copy().items():
            for i in range(len(data)):
                time_diff = abs(time_difference(formatted_timestamp, self.plate_info[plate][i][0][0]))
                if time_diff > time_thresh:
                    if plate not in del_index:
                        del_index[plate] = []
                    del_index[plate].append(i)
                if plate not in input_info:
                    input_info[plate] = []
                input_info[plate].append(data[i])
                if data[i][0][1] not in stake_info:
                    stake_info[data[i][0][1]] = []
                stake_info[data[i][0][1]].append(data[i])
        stake = {"ZW1":"K1660+950", "ZW2":"K1660+100", "HW1":"K1664+320", "HW6":"K1649+770", "HW3":"K1664+275", "HW7":"K1649+740", "ZW3":"K1660+980", "ZW4":"K1660+130", "TLS_3_1":"K1656+837", "TLS_3_2":"K1655+155", "TLS_4_1":"K1653+460", "TLS_4_2":"K1651+756", "TLS_1_1":"K1651+749", "TLS_1_2":"K1653+549", "TLS_2_1":"K1655+154", "TLS_2_2":"K1656+840"}
        uporgcode = ["HW7", "TLS_1_1", "TLS_1_2", "TLS_2_1", "TLS_2_2", "ZW4", "ZW3", "HW3"]
        downorgcode = ["HW1", "ZW1", "ZW2", "TLS_3_1", "TLS_3_2", "TLS_4_1", "TLS_4_2", "HW6"]
        speed_list = {}
        for license_code, data in input_info.items():
            for i in range(len(data)):
                stake_id = [row[0][1] for row in data]
                if data[i][0][1] in uporgcode and license_code != '车牌' and license_code != '默A00000':
                    if i+1 < len(data) and uporgcode.index(data[i][0][1]) + 1 < len(uporgcode):
                        if data[i+1][0][1] in uporgcode and data[i+1][0][1] != data[i][0][1]:
                            distance_km, distance_m = calculate_distance(stake[data[i][0][1]], stake[data[i+1][0][1]])
                            time_diff = time_difference(data[i][0][0], data[i+1][0][0])
                            speed = (distance_km * 1000 + distance_m) / time_diff
                            if (data[i][0][1], data[i+1][0][1]) not in speed_list:
                                speed_list[(data[i][0][1], data[i+1][0][1])] = []
                            speed_list[(data[i][0][1], data[i+1][0][1])].append(speed)
                elif data[i][0][1] in downorgcode and license_code != '车牌' and license_code != '默A00000':
                    if i+1 < len(data) and downorgcode.index(data[i][0][1]) + 1 < len(downorgcode):
                        if data[i+1][0][1] in downorgcode and data[i+1][0][1] != data[i][0][1]:
                            distance_km, distance_m = calculate_distance(stake[data[i][0][1]], stake[data[i+1][0][1]])
                            time_diff = time_difference(data[i][0][0], data[i+1][0][0])
                            speed = (distance_km * 1000 + distance_m) / time_diff
                            if (data[i][0][1], data[i+1][0][1]) not in speed_list:
                                speed_list[(data[i][0][1], data[i+1][0][1])] = []
                            speed_list[(data[i][0][1], data[i+1][0][1])].append(speed)

        result = []
        del_sn = []
        for sn, data in speed_list.copy().items():
            if sn[0] in uporgcode and sn[1] in uporgcode:
                if (sn[0], uporgcode[uporgcode.index(sn[0]) + 1]) in speed_list.keys():
                    if (sn[0], uporgcode[uporgcode.index(sn[0]) + 1]) not in del_sn:
                        del_sn.append((sn[0], uporgcode[uporgcode.index(sn[0]) + 1]))
            elif sn[0] in downorgcode and sn[1] in downorgcode:
                if (sn[0], downorgcode[downorgcode.index(sn[0]) + 1]) in speed_list.keys():
                    if (sn[0], downorgcode[downorgcode.index(sn[0]) + 1]) not in del_sn:
                        del_sn.append((sn[0], downorgcode[downorgcode.index(sn[0]) + 1]))
        for key in del_sn:
            for sn in speed_list.copy().keys():
                if sn[0] == key[0] and sn[1] != key[1]:
                    del speed_list[sn]

        stake_pair_all = [('HW1', 'ZW1'), ('ZW1', 'ZW2'), ('ZW2', 'TLS_3_1'), ('TLS_3_1', 'TLS_3_2'), ('TLS_3_2', 'TLS_4_1'), ('TLS_4_1', 'TLS_4_2'), ('TLS_4_2', 'HW6'), \
            ('HW7', 'TLS_1_1'), ('TLS_1_1', 'TLS_1_2'), ('TLS_1_2', 'TLS_2_1'), ('TLS_2_1', 'TLS_2_2'), ('TLS_2_2', 'ZW4'), ('ZW4', 'ZW3'), ('ZW3', 'HW3')]
        for key in speed_list.keys():
            for sn, data in stake_info.items():
                if key not in stay_in_stake_veh_num:
                    stay_in_stake_veh_num[key] = 0
                if sn == key[0]:
                    stay_in_stake_veh_num[key] = len(data) - len(speed_list[key])
            for i in stake_pair_all:
                if i[0] == key[0] and i[1] != key[1]:
                    continue
                elif i not in speed_list.keys():
                    if i not in stay_in_stake_veh_num and i[0] in stake_info.keys():
                        stay_in_stake_veh_num[i] = 0
                    if i[0] in stake_info.keys():
                        stay_in_stake_veh_num[i] = len(stake_info[i[0]])
        interval_long_info = stay_in_stake_veh_num.copy()

        lon_lat = {
                    "HW1": [106.90458785, 30.33287997],
                    "ZW1": [106.9291, 30.31261],
                    "ZW2": [106.93471, 30.30665],
                    "HW6": [107.01842, 30.25336],
                    "TLS_4_2": [107.0000207, 30.2608549],
                    "HW3": [106.9048189, 30.3325609],
                    "ZW3": [106.92912, 30.31298],
                    "HW7": [107.01873, 30.2534],
                    "TLS_1_1": [107.0009195, 30.2606119],
                    "ZW4": [106.93473, 30.30705],
                    "TLS_1_2": [106.9882976, 30.2712984],
                    "TLS_3_1": [106.9622785, 30.2931042],
                    "TLS_3_2": [106.9752273, 30.2819368],
                    "TLS_2_1": [106.9752964, 30.2823442],
                    "TLS_2_2": [106.962415, 30.2934835],
                    "TLS_4_1": [106.9881101, 30.2710593],
                    }
        congestion = {
            1: "畅通",
            2: "轻度拥堵",
            3: "中度拥堵",
            4: "严重拥堵",
        }
        event_id = {"ZW1": 1001, "ZW2": 1002, "HW1": 1003, "HW6": 1004, "HW3": 1005, "HW7": 1006, "ZW3": 1007, "ZW4": 1008, "TLS_3_1": 1009, "TLS_3_2": 1010, "TLS_4_1": 1011, "TLS_4_2": 1012, "TLS_1_1": 1013, "TLS_1_2": 1014, "TLS_2_1": 1015, "TLS_2_2": 1016}
        for sn, data in speed_list.items():
            average_travel_speed = sum(data) / len(data)
            if sn[0] in uporgcode and sn[1] in uporgcode:
                distance_km, distance_m = calculate_distance(stake[sn[0]], stake[sn[1]])
            elif sn[0] in downorgcode and sn[1] in downorgcode:
                distance_km, distance_m = calculate_distance(stake[sn[0]], stake[sn[1]])
            average_density = (len(speed_list[sn]) + stay_in_stake_veh_num[sn]) * (3600 / time_thresh) / (average_travel_speed * 3.6)

            del interval_long_info[sn]
            if ((average_travel_speed * 3.6) < 30 and average_density > 60):
                event_dict = {}
                datetime.strptime(formatted_timestamp, '%Y-%m-%dT%H:%M:%S.%f')
                dt_object = dt
                # formatted_time = dt_object.strftime('%Y-%m-%d %H:%M:%S')
                formatted_time = datetime.strptime(formatted_timestamp, '%Y-%m-%dT%H:%M:%S.%f').strftime('%Y-%m-%d %H:%M:%S')
                direction = 0
                if sn[0] in uporgcode:
                    direction = 0
                elif sn[0] in downorgcode:
                    direction = 1
                event_dict["orgCode"] = sn[1]
                event_dict["upOrgCode"] = sn[0]
                event_dict["intervalSpeed"] = average_travel_speed
                event_dict["totalFlow"] = len(data)
                event_dict["congestion"] = congestion[4]
                event_dict["globalTime"] = formatted_time
                event_dict["secLevel"] = 4
                event_dict["lastTimeIndex"] = 1
                event_dict["info"] = ""
                event_dict["updateTime"] = formatted_time
                event_dict["timestamp"] = formatted_time
                event_dict["direction"] = direction
                event_dict["sNum"] = stake[sn[0]]
                event_dict["eNum"] = stake[sn[1]]
                event_dict["sLon"] = lon_lat[sn[0]][0]
                event_dict["sLat"] = lon_lat[sn[0]][1]
                event_dict["eLon"] = lon_lat[sn[1]][0]
                event_dict["eLat"] = lon_lat[sn[1]][1]
                event_dict["isBreakdown"] = 0
                event_dict["eventId"] = event_id[sn[0]]
                event_dict["eventInfo"] = ""
                result.append(event_dict)
        for sn, count in interval_long_info.copy().items():
            average_travel_speed = 0
            B5 = 1
            if B5 and count > 200:
                event_dict = {}
                datetime.strptime(formatted_timestamp, '%Y-%m-%dT%H:%M:%S.%f')
                dt_object = dt
                # formatted_time = dt_object.strftime('%Y-%m-%d %H:%M:%S')
                formatted_time = datetime.strptime(formatted_timestamp, '%Y-%m-%dT%H:%M:%S.%f').strftime('%Y-%m-%d %H:%M:%S')
                direction = 0
                if sn[0] in uporgcode:
                    direction = 0
                elif sn[0] in downorgcode:
                    direction = 1
                event_dict["orgCode"] = sn[1]
                event_dict["upOrgCode"] = sn[0]
                event_dict["intervalSpeed"] = average_travel_speed
                event_dict["totalFlow"] = count
                event_dict["congestion"] = congestion[4]
                event_dict["globalTime"] = formatted_time
                event_dict["secLevel"] = 4
                event_dict["lastTimeIndex"] = 1
                event_dict["info"] = ""
                event_dict["updateTime"] = formatted_time
                event_dict["timestamp"] = formatted_time
                event_dict["direction"] = direction
                event_dict["sNum"] = stake[sn[0]]
                event_dict["eNum"] = stake[sn[1]]
                event_dict["sLon"] = lon_lat[sn[0]][0]
                event_dict["sLat"] = lon_lat[sn[0]][1]
                event_dict["eLon"] = lon_lat[sn[1]][0]
                event_dict["eLat"] = lon_lat[sn[1]][1]
                event_dict["isBreakdown"] = 0
                event_dict["eventId"] = event_id[sn[0]]
                event_dict["eventInfo"] = ""
                result.append(event_dict)
        for key, value in del_index.items():
            for i in range(len(value)-1, -1, -1):
                del self.plate_info[key][value[i]]
                if not self.plate_info[key]:
                    del self.plate_info[key]
        if result != None:
            if len(result):
                self.congestion_kakou_queue.put(result)

        return del_index, result

    def merge_data_process(self, message, congestion_queue):
        # while True:
        timestamp_now = 0
        if "sn" in message:
            # timestamp_now = time.time()
            # vehicle_info = json.loads(message.value.decode('utf-8'))
            csv_data = kakou_data_process(message)
            if csv_data[0][2] not in self.plate_info:
                self.plate_info[csv_data[0][2]] = []
            if csv_data[0][2] != '车牌' and csv_data[0][2] != '默A00000':
                self.plate_info[csv_data[0][2]].append(csv_data)
                # 使用 strptime 将字符串转换为 datetime 对象
                dt_save = datetime.strptime(csv_data[0][0], '%Y-%m-%dT%H:%M:%S.%f')
                # 将 datetime 对象转换为时间戳（秒级别）
                timestamp_now = dt_save.timestamp()
            if timestamp_now - self.timestamp_B5 > 60:
                del_index, B5 = self.kakou_congestion_detect()
                self.timestamp_B5 = timestamp_now
                print("卡口算法: ", timestamp_now)
        elif "orgCode" in message:
            # vehicle_info = json.loads(message.value.decode('utf-8'))
            result = lidar_data_process(message)
            if result != None:
                combined_data = np.array(result)
                # timestamp_now = time.time()
                if len(result):
                    timestamp_now = combined_data[0][4]
                    self.traffic_flows[result[0][-2]].use(combined_data,True,timestamp_now)
                    now_frame_data = self.traffic_flows[result[0][-2]].get_B5()
                    if now_frame_data != None:
                        self.congestion_lidar_queue.put(now_frame_data)
        elif "ip" in message:
            topic = message.get("topic")
            topic_ip = int(topic.split('.')[-1])
            vehicle_info = get_info_from_raw(message,topic_ip)
            timestamp_now = time.time()
            input_info = np.array(vehicle_info)
            if len(input_info):
                self.traffic_flow.use(input_info,True,timestamp_now)
                B5 = self.traffic_flow.get_B5()
                if B5 != None:
                    self.congestion_lidar_queue.put(B5)

        # 上报雷达算法和卡口算法的并集拥堵结果
        #===============#
        # cur_time = time.time()
        if timestamp_now - self.timestamp_event > 60:
            self.timestamp_event = timestamp_now
            orgcode_map = defaultdict(list)
            B5_send = []
            while not self.congestion_lidar_queue.empty():
                B5_data = self.congestion_lidar_queue.get()
                org_code = B5_data[0]['upOrgCode']
                orgcode_map[org_code].append(B5_data)
            while not self.congestion_kakou_queue.empty():
                B5_data = self.congestion_kakou_queue.get()
                for data in B5_data:
                    org_code = data['upOrgCode']
                    orgcode_map[org_code].append([data])
            for upOrgCode, messages in orgcode_map.items():
                B5_send.append(messages[-1][0])
            B5_send_copy = B5_send
            stake_pair_all = [('HW1', 'ZW1'), ('ZW1', 'ZW2'), ('ZW2', 'TLS_3_1'), ('TLS_3_1', 'TLS_3_2'), ('TLS_3_2', 'TLS_4_1'), ('TLS_4_1', 'TLS_4_2'), ('TLS_4_2', 'HW6'), \
            ('HW7', 'TLS_1_1'), ('TLS_1_1', 'TLS_1_2'), ('TLS_1_2', 'TLS_2_1'), ('TLS_2_1', 'TLS_2_2'), ('TLS_2_2', 'ZW4'), ('ZW4', 'ZW3'), ('ZW3', 'HW3')]
            for i in range(len(B5_send_copy)):
                for j in range(i + 1, len(B5_send_copy)):
                    if B5_send_copy[i]['upOrgCode'] == B5_send_copy[j]['upOrgCode'] and B5_send_copy[i]['orgCode'] != B5_send_copy[j]['orgCode']:
                        if (B5_send_copy[i]['upOrgCode'], B5_send_copy[i]['orgCode']) in stake_pair_all:
                            del B5_send[i]
                        elif (B5_send_copy[j]['upOrgCode'], B5_send_copy[j]['orgCode']) in stake_pair_all:
                            del B5_send[j]
                    elif B5_send_copy[i]['upOrgCode'] != B5_send_copy[j]['upOrgCode'] and B5_send_copy[i]['orgCode'] == B5_send_copy[j]['orgCode']:
                        if (B5_send_copy[i]['upOrgCode'], B5_send_copy[i]['orgCode']) in stake_pair_all:
                            del B5_send[i]
                        elif (B5_send_copy[j]['upOrgCode'], B5_send_copy[j]['orgCode']) in stake_pair_all:
                            del B5_send[j]
            if B5_send != None:
                if len(B5_send):
                    for i in B5_send:
                        congestion_queue.put(i)
            else:
                print("Queue is empty, no message sent.")

    def get_flag(self, flag_q):
        '''
        监控线程是否需要结束
        '''
        while not self.flag:
            while not flag_q.empty():
                flag = flag_q.get(timeout=0.1)
                if flag:
                    self.flag = True

            time.sleep(0.1)

    def run(self, lidar_queue, kakou_queue, congestion, flag_q):
        # 启动监控线程
        threading.Thread(target=self.get_flag, args=(flag_q,)).start()

        while not self.flag:
            time.sleep(0.01)
            try:
                while not lidar_queue.empty():
                    message_A = lidar_queue.get()
                    self.merge_data_process(message_A, congestion)
                while not kakou_queue.empty():
                    message_B = kakou_queue.get()
                    self.merge_data_process(message_B, congestion)
            except Exception as e:
                print("congestion error:", e)


if __name__ == "__main__": 
    file_path_A = "/data/tongluoshan/radar_lidar_kakou_merge/data/20250125_lidar.json"
    file_path_B = "/data/tongluoshan/20250125-20250205/new/2025-01-25.json"
    # with open(file_path_A, 'r', encoding='utf-8') as f_A, open(file_path_B, 'r', encoding='utf-8') as f_B:
    #     line_A = f_A.readline()
    #     line_B = f_B.readline()
    #     while line_A or line_B:
    #         message_A, message_B = None, None
    #         t_A, t_B = None, None
    #         if line_A:
    #             try:
    #                 message_A = json.loads(line_A)
    #                 t_A = datetime.strptime(message_A["globalTimeStamp"], "%Y-%m-%d %H:%M:%S:%f")
    #             except (json.JSONDecodeError, ValueError) as e:
    #                 print(f"激光数据解析错误 (A): {e}")
    #                 message_A = None  # 跳过当前行
    #         if line_B:
    #             try:
    #                 message_B = json.loads(line_B)
    #                 t_B = datetime.strptime(message_B["timestamp"], "%Y-%m-%dT%H:%M:%S.%f")
    #             except (json.JSONDecodeError, ValueError) as e:
    #                 print(f"卡口解析错误 (B): {e}")
    #                 message_B = None  # 跳过当前行
    #         # 发送数据，按时间顺序·
    #         congestion_queue_ = queue.Queue()
    #         if message_A and (not message_B or t_A <= t_B):
    #             congestion_queue_ = merge_data_process(message_A)
    #             # print(f"Sent to {GLOBAL_TOPIC}: {t_A}")
    #             line_A = f_A.readline()  # 读取 A 的下一行
    #         elif message_B:
    #             congestion_queue_ = merge_data_process(message_B)
    #             # print(f"Sent to {KAKOU_TOPIC}: {t_B}")
    #             line_B = f_B.readline()  # 读取 B 的下一行
    #         while  not congestion_queue_.empty():
    #             B5_data = congestion_queue_.get()
    #             print("B5data: ", B5_data)
    #         time.sleep(0.0001)